OpenBao Admin & Operations Guide

Comprehensive documentation for the Secunetics OpenBao infrastructure deployed on 10.11.11.123 (vault.secunetics.net).

1. Architecture Overview

  • Platform: OpenBao (FOSS Fork of HashiCorp Vault)
  • Deployment: Docker Compose (Single Node)
  • Storage Backend: Integrated Raft Storage (Persistent local volume)
  • Host Machine: lab-microservices (10.11.11.123)
  • Domain: vault.secunetics.net
  • Authentication: Google Workspace OIDC (Humans), AppRole (Machines)

2. Deployment & Configuration

The system is deployed via Docker. The directory structure on the host machine is:

~/openbao/
├── docker-compose.yml
├── config/
│   ├── bao.hcl
│   ├── bao.crt (Signed by Lab CA)
│   └── bao.key
├── data/       (Persistent Raft DB)
└── logs/       (Audit logs)

docker-compose.yml

version: '3.8'
services:
  openbao:
    image: openbao/openbao:latest
    container_name: openbao
    ports:
      - "443:8200"
      - "8201:8201" 
    restart: unless-stopped
    command: server
    environment:
      BAO_ADDR: "https://127.0.0.1:8200"
      BAO_API_ADDR: "https://127.0.0.1:8200"
    volumes:
      - ./config:/openbao/config
      - ./data:/openbao/data
      - ./logs:/openbao/logs

config/bao.hcl

ui = true

storage "raft" {
  path    = "/openbao/data"
  node_id = "bao-node-1"
}

listener "tcp" {
  address                  = "0.0.0.0:8200"
  tls_disable              = "false" 
  tls_cert_file            = "/openbao/config/bao.crt"
  tls_key_file             = "/openbao/config/bao.key"
  tls_disable_client_certs = "true" # Prevents browser mTLS popups
}

api_addr     = "https://10.11.11.123"
cluster_addr = "https://127.0.0.1:8201"

# Declarative Audit Device
audit "file" "audit-log" {
  description = "Shared lab audit log"
  options = {
    file_path = "/openbao/logs/audit.log"
  }
}

3. Initialization & Unsealing

OpenBao uses a master key to encrypt data. When the container starts or restarts, it is sealed and requires manual intervention to unlock.

How to Unseal (Do this after every reboot)

Log into the host machine and execute the unseal command three times, providing 3 different unseal keys:

sudo docker exec -it openbao bao operator unseal

Emergency Rebuild (Complete Data Loss)

If you lose the data volume or deploy to a new server, start the container and run:
sudo docker exec -it openbao bao operator init
SAVE THE 5 UNSEAL KEYS AND INITIAL ROOT TOKEN IMMEDIATELY.

4. TLS Certificates (Crucial Permissions)

OpenBao requires HTTPS. Certificates are generated via OpenSSL and signed by the internal Lab CA. Important: The OpenBao container runs as a restricted user (UID 100), not root.

Fixing Certificate Permission Denied Errors

If OpenBao crashes on startup with a TLS read error, the host machine permissions are wrong. Run this on the host:

sudo chown 100:100 config/bao.key config/bao.crt
sudo chmod 600 config/bao.key
sudo chmod 644 config/bao.crt
sudo docker restart openbao

5. Policies & Secrets Engines

To configure policies, drop into the container and bypass TLS verification for the local session:

sudo docker exec -it openbao sh
export BAO_ADDR="https://127.0.0.1:8200"
export BAO_SKIP_VERIFY="true"
bao login # (Use Root Token)

The Shared Engine

Users and scripts operate out of a KV-V2 engine located at lab-shared/. To recreate it:

bao secrets enable -path=lab-shared kv-v2

The Developer Policy (dev-policy)

bao policy write dev-policy - <<EOF
# Allow full access to shared secrets
path "lab-shared/data/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
path "lab-shared/metadata/*" {
  capabilities = ["read", "list", "delete"]
}
# Allow users to manage their AppRole SecretIDs in the browser
path "auth/approle/role/lab-shared-app/role-id" {
  capabilities = ["read"]
}
path "auth/approle/role/lab-shared-app/secret-id" {
  capabilities = ["update"]
}
EOF

6. Google Workspace SSO (OIDC)

Human access is governed by Google SSO locked to the secunetics.com domain.

OIDC Setup Commands

bao auth enable oidc

# Configure the provider
bao write auth/oidc/config \
    oidc_discovery_url="https://accounts.google.com" \
    oidc_client_id="<GCP_CLIENT_ID>" \
    oidc_client_secret="<GCP_CLIENT_SECRET>" \
    default_role="google-user"

# Create the standard user role (Maps to dev-policy)
bao write auth/oidc/role/google-user - <<EOF
{
  "user_claim": "email",
  "oidc_scopes": ["email", "profile"],
  "allowed_redirect_uris": [
    "https://vault.secunetics.net/ui/vault/auth/oidc/oidc/callback",
    "http://localhost:8250/oidc/callback"
  ],
  "bound_claims": { "hd": "secunetics.com" },
  "policies": ["dev-policy"],
  "ttl": "8h"
}
EOF

# Create the Admin Role (Requires explicit email match)
bao write auth/oidc/role/admin-user - <<EOF
{
  "user_claim": "email",
  "oidc_scopes": ["email", "profile"],
  "allowed_redirect_uris": [
    "https://vault.secunetics.net/ui/vault/auth/oidc/oidc/callback",
    "http://localhost:8250/oidc/callback"
  ],
  "bound_claims": { "email": "YOUR_EMAIL@secunetics.com" },
  "policies": ["admin-policy"],
  "ttl": "8h"
}
EOF

7. AppRole (Machine Identities)

Microservices authenticate using AppRole. Users self-serve their SecretID via the Web UI Browser CLI.

Admin Setup: Creating the AppRole

bao auth enable approle

bao write auth/approle/role/lab-shared-app \
    secret_id_ttl=0 \
    token_num_uses=0 \
    token_ttl=1h \
    token_max_ttl=4h \
    policies="dev-policy"

User Workflow: Generating Credentials in Web CLI

Users execute these in the Browser terminal (>_):

# Get the Role ID
read auth/approle/role/lab-shared-app/role-id

# Generate a Secret ID (Must use -f flag!)
write -f auth/approle/role/lab-shared-app/secret-id

8. Routine Maintenance

Audit Logs

Audit logging is strictly enabled via the bao.hcl file. The log file resides on the host at ~/openbao/logs/audit.log.
Action Required: Configure logrotate on the Ubuntu host machine to rotate and compress this file weekly, or it will eventually fill the host storage.

Raft Snapshots (Backups)

To take a backup of the encrypted database, run:

export BAO_ADDR="https://vault.secunetics.net"
bao login -method=oidc -role=admin-user
bao operator raft snapshot save bao_backup_$(date +%F).snap

TLS Certificate Renewal

Before the lab CA certificate expires:

  1. Generate a new CSR using the original csr.conf (ensure SANs are included).
  2. Sign it with the Lab CA.
  3. Replace bao.crt in the config directory.
  4. Run sudo chown 100:100 config/bao.crt.
  5. Restart the container and unseal.